package com.gitee.loyo.act.remote

import kotlinx.coroutines.runBlocking
import com.gitee.loyo.KSQL
import com.gitee.loyo.Utils
import com.gitee.loyo.act.*
import com.gitee.loyo.interfaces.LazyReadMapper
import com.gitee.loyo.interfaces.TypeReference
import java.lang.reflect.Method
import kotlin.reflect.KClass

object RemoteTransferorFactory: TransferorFactory {

    override fun transfer(model: Model<*, *>): Transferor = object: Transferor {

        init {
            model.selectClause = model.selectColumns?.map { it.getLabelName() }
        }

        override fun asLazyReadMapper(): LazyReadMapper{
            val responseText = DualModels.execute(ModelExecution.doRead(model)).ifBlank{ null }
            return object : LazyReadMapper{

                override fun <T : Any> `as`(kType: KClass<T>)
                = responseText?.let {
                    if(Utils.isNotObject(kType)){
                        DualModels.mapper.mappingList(it, object: TypeReference<Map<String, T>>(Map::class.java){})?.also {
                            if(KSQL.strictOneRow && it.size > 1) throw RuntimeException("返回结果大于1行")
                        }?.firstOrNull()?.let { map ->
                            map.values.firstOrNull()
                        }?.let { value ->
                            Utils.tryConvert(value, kType)
                        }
                    }else{
                        `as`(object: TypeReference<T>(kType.java){})
                    }
                }

                override fun <T : Any> `as`(typeRef: TypeReference<T>)
                = responseText?.let {
                    DualModels.mapper.mappingList(it, typeRef)?.also {
                        if(KSQL.strictOneRow && it.size > 1) throw RuntimeException("返回结果大于1行")
                    }?.firstOrNull()
                }

                override fun <T : Any> asList(kType: KClass<T>)
                = asList(object: TypeReference<T>(kType.java){})

                override fun <T : Any> asList(typeRef: TypeReference<T>)
                = responseText?.let { DualModels.mapper.mappingList(it, typeRef) }?: emptyList()

            }
        }

        override fun insert()
        = DualModels.execute(ModelExecution.doAdd(model)).ifBlank { null }?.toIntOrNull()?:0

        override fun create()
        = DualModels.execute(ModelExecution.doCreate(model)).ifBlank { null }?.let { it.toLongOrNull()?:it }

        override fun update()
        = DualModels.execute(ModelExecution.doUpdate(model)).toIntOrNull()?:0

        override fun delete()
        = DualModels.execute(ModelExecution.doDelete(model)).toIntOrNull()?:0

    }

    override fun invoke(cls: Class<*>, daoMethod: Method, args: Map<String, Any?>): Any? {
        val responseText = DualModels.invoke(RemoteInvocation(
            cls.name,
            daoMethod.declaringClass.name,
            Utils.sign(daoMethod),
            args
        ))
        return if(daoMethod.returnType == List::class.java){
            responseText.ifBlank { null }?.let {
                DualModels.mapper.mapping(it, object: TypeReference<Any>(daoMethod.genericReturnType){})
            }?:null
        }else{
            responseText.ifBlank { null }?.let {
                DualModels.mapper.mapping(it, object: TypeReference<Any>(daoMethod.returnType){})
            }?:null
        }
    }

}